package study.week05.gateway.outbound;

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.util.ReferenceCountUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import study.week05.gateway.entity.GatewayContext;
import study.week05.gateway.filter.CustomHttpFilter;
import study.week05.gateway.router.CustomRouter;
import study.week05.uti.HttpClientUtil;
import study.week05.uti.UidUtil;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

public class JmsHandler {
    /**
     * 每个uid的最大超时时间，避免服务没有响应时，无法清除对应的对象。所以这里写了个checkExpiring()方法清除超时的请求,避免内存泄漏的问题
     */
    long maxTimeout=1000*60*5;
    JmsTemplate jmsTemplate;
    /**
     * 如果有请求服务没有响应，部分数据会一直在内存中无法清除。所以这里写了个checkExpiring()方法清除超时的请求，避免内存泄漏
     */
    ConcurrentHashMap<String, GatewayContext> contextMap = new ConcurrentHashMap<>();

    public JmsHandler(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    /**
     * 清理超时的请求
     */
    public void checkExpiring(){
        Set<Map.Entry<String, GatewayContext>> entrySet = contextMap.entrySet();
        for (Map.Entry<String, GatewayContext> entry : entrySet) {
            long timestampTimeout = entry.getValue().getTimestamp() + maxTimeout;

            if(timestampTimeout >System.currentTimeMillis()  ){
                contextMap.remove(entry.getKey());
            }

        }
    }

    /**
     *
     * @param fullRequest
     * @param ctx
     */
    public void sendRequest(FullHttpRequest fullRequest, ChannelHandlerContext ctx , String server) {
        String uri = fullRequest.uri();
        jmsTemplate.send(server, session -> {
            String uid = UidUtil.generateUid();
            contextMap.put(uid,new GatewayContext(ctx,fullRequest,System.currentTimeMillis()));
            return session.createTextMessage(uid +":"+uri);
        });

    }
    public GatewayContext getGatewayContext(String uid){
        checkExpiring();
        return contextMap.remove(uid);
    }
    public void doResponse(FullHttpRequest fullRequest, ChannelHandlerContext ctx ,FullHttpResponse response){
        if(response != null){
            if (!HttpUtil.isKeepAlive(fullRequest)) {
                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
            } else {
                response.headers().set(CONNECTION, KEEP_ALIVE);
                ctx.write(response);
            }
            ctx.flush();
        }
        ReferenceCountUtil.release(fullRequest);
    }
    public FullHttpResponse receiveResponse( FullHttpRequest fullRequest, ChannelHandlerContext ctx ,String body){
        FullHttpResponse response = null;
        try {

            response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(body.getBytes(StandardCharsets.UTF_8)));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length", response.content().readableBytes());


        } catch (Exception e) {
            System.out.println("处理出错:"+e.getMessage());
            response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
        }
        return response;
    }


}
